﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace BLLog
{
    /// <summary>
    /// 日志记录器
    /// </summary>
    public class Logger
    {
        /// <summary>
        /// 日志文件夹
        /// </summary>
        public string directory = "logs";

        /// <summary>
        /// 日志名称前缀
        /// </summary>
        public string prefix = "bllog";

        /// <summary>
        /// 日志保留天数，默认保留一年
        /// </summary>
        public int days = 367;

        /// <summary>
        /// 日志锁
        /// </summary>
        private readonly Dictionary<LogLevel, object> lockers;

        /// <summary>
        /// 创建日志记录器
        /// </summary>
        public Logger()
        {
            #region 初始化日志锁

            lockers = new Dictionary<LogLevel, object>
            {
                { LogLevel.Debug, new object() },
                { LogLevel.Trace, new object() },
                { LogLevel.Info, new object() },
                { LogLevel.Warn, new object() },
                { LogLevel.Error, new object() },
                { LogLevel.Fatal, new object() }
            };
            #endregion

            #region 创建日志文件夹

            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }
            #endregion

            #region 创建删除过期日志的任务
            Task.Run(async () =>
            {
                while (true)
                {
                    DateTime dateTime = DateTime.Now - new TimeSpan(days, 0, 0, 0);
                    string pattern = @"\d{4}-\d{2}-\d{2}";
                    Regex regex = new Regex(pattern);
                    foreach (FileInfo fileInfo in new DirectoryInfo(directory).GetFiles())
                    {
                        if (fileInfo.Extension.ToLower() == ".log")
                        {
                            try
                            {
                                Match match = regex.Match(fileInfo.Name);
                                DateTime dt = DateTime.Parse(match.Value);
                                if (dt < dateTime)
                                {
                                    fileInfo.Delete();
                                }
                            }
                            catch { }
                        }
                    }

                    //每天检查一次
                    await Task.Delay(1000 * 24 * 60 * 60);
                }
            });
            #endregion
        }

        /// <summary>
        /// 追溯
        /// </summary>
        /// <param name="message">信息</param>
        public void Trace(string message)
        {
            string method = System.Reflection.MethodBase.GetCurrentMethod().Name;
            string filepath = $"{directory}/{prefix}_{method}_{DateTime.Now:yyyy-MM-dd}.log";
            message = $"[{DateTime.Now:HH:mm:ss}] [{method}]{Environment.NewLine}{message}{Environment.NewLine}{Environment.NewLine}";
            lock (lockers[ParseLogLevel(method)])
            {
                File.AppendAllText(filepath, message);
            }
        }

        /// <summary>
        /// 调试
        /// </summary>
        /// <param name="message">信息</param>
        public void Debug(string message)
        {
            string method = System.Reflection.MethodBase.GetCurrentMethod().Name;
            string filepath = $"{directory}/{prefix}_{method}_{DateTime.Now:yyyy-MM-dd}.log";
            message = $"[{DateTime.Now:HH:mm:ss}] [{method}]{Environment.NewLine}{message}{Environment.NewLine}{Environment.NewLine}";
            lock (lockers[ParseLogLevel(method)])
            {
                File.AppendAllText(filepath, message);
            }
        }

        /// <summary>
        /// 信息
        /// </summary>
        /// <param name="message">信息</param>
        public void Info(string message)
        {
            string method = System.Reflection.MethodBase.GetCurrentMethod().Name;
            string filepath = $"{directory}/{prefix}_{method}_{DateTime.Now:yyyy-MM-dd}.log";
            message = $"[{DateTime.Now:HH:mm:ss}] [{method}]{Environment.NewLine}{message}{Environment.NewLine}{Environment.NewLine}";
            lock (lockers[ParseLogLevel(method)])
            {
                File.AppendAllText(filepath, message);
            }
        }

        /// <summary>
        /// 警告
        /// </summary>
        /// <param name="message">信息</param>
        public void Warn(string message)
        {
            string method = System.Reflection.MethodBase.GetCurrentMethod().Name;
            string filepath = $"{directory}/{prefix}_{method}_{DateTime.Now:yyyy-MM-dd}.log";
            message = $"[{DateTime.Now:HH:mm:ss}] [{method}]{Environment.NewLine}{message}{Environment.NewLine}{Environment.NewLine}";
            lock (lockers[ParseLogLevel(method)])
            {
                File.AppendAllText(filepath, message);
            }
        }

        /// <summary>
        /// 错误
        /// </summary>
        /// <param name="message">信息</param>
        public void Error(string message)
        {
            string method = System.Reflection.MethodBase.GetCurrentMethod().Name;
            string filepath = $"{directory}/{prefix}_{method}_{DateTime.Now:yyyy-MM-dd}.log";
            message = $"[{DateTime.Now:HH:mm:ss}] [{method}]{Environment.NewLine}{message}{Environment.NewLine}{Environment.NewLine}";
            lock (lockers[ParseLogLevel(method)])
            {
                File.AppendAllText(filepath, message);
            }
        }

        /// <summary>
        /// 致命
        /// </summary>
        /// <param name="message">信息</param>
        public void Fatal(string message)
        {
            string method = System.Reflection.MethodBase.GetCurrentMethod().Name;
            string filepath = $"{directory}/{prefix}_{method}_{DateTime.Now:yyyy-MM-dd}.log";
            message = $"[{DateTime.Now:HH:mm:ss}] [{method}]{Environment.NewLine}{message}{Environment.NewLine}{Environment.NewLine}";
            lock (lockers[ParseLogLevel(method)])
            {
                File.AppendAllText(filepath, message);
            }
        }

        /// <summary>
        /// 日志等级
        /// </summary>
        /// <param name="loglevel">日志等级</param>
        /// <returns></returns>
        private static LogLevel ParseLogLevel(string logLevel)
        {
            foreach (LogLevel level in Enum.GetValues(typeof(LogLevel)))
            {
                if (level.ToString() == logLevel)
                {
                    return level;
                }
            }
            return LogLevel.Trace;
        }

        /// <summary>
        /// 日志等级
        /// </summary>
        internal enum LogLevel
        {
            Trace,
            Debug,
            Info,
            Warn,
            Error,
            Fatal
        }
    }
}
